Ich stelle das Thema mal online zur Diskussion:
Eine Assemblerroutine maximal schnell und effektiv um ein Plot/Drawto in Antic D nachzubilden...
Ideen??
Ich stelle das Thema mal online zur Diskussion:
Eine Assemblerroutine maximal schnell und effektiv um ein Plot/Drawto in Antic D nachzubilden...
Ideen??
... ich lege mal los ...
Lies mal den Artikel "Schnelle Vektoren in Action!" aus ATARIMAGAZIN von P.Finzel. Dort beschreibt er einen Algorithmus, der schneller ist als die OS Routine.
https://atariwiki.org/wiki/Wiki.jsp?page=Action#section-Action-ATARImagazin
... vielen Dank. Sehr interessanter Artikel (wie immer bei Peter Finzel). Leider in Action! geschrieben. Action! ist sicherlich eine höchst interessante Sprache, die ich leider nicht nutze. Vielleicht kann man das mal irgendwie in Eclipse implementieren - das wäre doch was für Peter (JAC)?!
Schau mal in den MADS examples Ordner. Dort findest Du fast draw.
PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo
Dr. Irata schrieb: ... vielen Dank. Sehr interessanter Artikel (wie immer bei Peter Finzel). Leider in Action! geschrieben.
http://www.atarimania.com/mags/pdf/Atari-Magazin-89-11-12.pdf
Seite 39 dürftest Du in Assembler fündig werden...
Leider habe ich in meinen Mads-Ordnern kein fast-draw gefunden ....
Das ist etwas versteckt. Habe mal kurz im github geschaut. Ich weiß, dass auch noch mehr Beispiele drin waren. Hier aber eines:
line.asm im examples Ordner

PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo
gefunden, läuft aber nicht....
Das ist nicht eigenständig, sondern gehört zur graphics library.
PP´s of STARSOFTBerlin____github|meine Webseite|Demozoo
... nun habe ich einige Vorlagen selber gesammelt und dank eurer Links auch Vorlagen und Alternativen gefunden ... alles toll und zum Teil sehr "fertig" aber auch komplex. Ich möchte aber eine ganz eigene Routine hier mit euch entwickeln, die möglichst schnell ist - am Ende wird sich zeigen, ob sie schnell und effektiv ist.
Wir wollen ja eine Gerade zeichnen und brauchen eigentlich die Steigung dafür. Die Steigung lässt sich einfach mathematisch bestimmen aus dem Quotienten der Differenzen der y- und x-Werte: m = (y2-y1)/(x2-x1) = dy / dx Am Ende vermeidet der Bresenham-Algorithmus dieses Teilen, da er prinzipiell zeitintensiv und schwierig ist.... ist das denn wirklich auch so. Ich muss ja zum zeichnen der Gerade nur einmal teilen - am Anfang - und danach setze ich nur noch die Pixel in Abhängigkeit der Steigung m. Wenn die Steigung m beispielsweise 3 beträgt, dann muss ich nach jeden Schritt nach vorne 3 Schritte hoch gehen usw.
Also muss zunächst eine schnelle Routine her fürs relativ einfache teilen:
SEC
LDA dy
loop SBC dx
INX
BCS loop
Danach steht im Register x die Steigung. Die Routine braucht 5 Zyklen plus x (Anzahl der Durchgänge) mal 8 Zyklen. 2 Sonderfälle sortieren wir gleich am Anfang aus: Die vertikale und die horizontale Linie. Die zeichnen wir direkt. Alles andere wird mittels der Steigung m gezeichnet.
Dr. Irata schrieb: Ich muss ja zum zeichnen der Gerade nur einmal teilen - am Anfang - und danach setze ich nur noch die Pixel in Abhängigkeit der Steigung m. Wenn die Steigung m beispielsweise 3 beträgt, dann muss ich nach jeden Schritt nach vorne 3 Schritte hoch gehen usw.
Wenn die Steigung z.B. 2.5 ist, bekommst Du für die "Unterschlagung" der Nachkommastellen mit Deiner Assemblerroutine "lustige" Ergebnisse...
Ich bin gespannt...
... das ist wahr... bin auch mal gespannt. Den Fehler muss man evt. ausbügeln. Das Verfahren ist ja auch nur eine Art Näherung.
Dr. Irata schrieb: Den Fehler muss man evt. ausbügeln. Das Verfahren ist ja auch nur eine Art Näherung.
Der Fehler muss in den Algorithmus einfließen.
Mit einem Algorithmus à la "nach zwei Pixel hoch, einen nach rechts" bekommst Du nicht immer eine Verbindung zwischen zwei Punkten:

Du kannst Dir eine Menge Zeit und Aufwand sparen (und hast dabei noch den schnellsten Algorithmus), wenn Du Bresenham anwendest...
hmmmm.... warum das Rad neu erfinden, wenn es nicht sicher ist, ob es runder und besser ist, als das bereits bestehende... Der Bresenham-Algorithmus ist ja speziell damals für die Linienzeichnung entwickelt worden. Die Theorie ist dabei mathematisch relativ logisch und die Umsetzung einfach. Als Beispiel hier die Umsetzung in Basic:
REM Bresenham-Algorithmus für eine Linie im ersten Oktanten in Pseudo-Basic
dx = xend-xstart
dy = yend-ystart
REM im ersten Oktanten muss 0 < dy <= dx sein
REM Initialisierungen
x = xstart
y = ystart
SETPIXEL x,y
fehler = dx/2
REM Pixelschleife: immer ein Schritt in schnelle Richtung, hin und wieder auch einer in langsame
WHILE x < xend
REM Schritt in schnelle Richtung
x = x + 1
fehler = fehler - dy
IF fehler < 0 THEN
REM Schritt in langsame Richtung
y = y + 1
fehler = fehler + dx
END IF
SETPIXEL x,y
WEND
... das kann man gut in Assembler konvertieren!

... nun habe ich es doch mal mit meiner Methode probiert - zunächst - und es klappt damit auch ganz gut. Die größte Schwierigkeit dabei war es eigentlich die Dinge mit einer vernünftigen Geschwindigkeit auch für später auf den Bildschirm zu bringen. Ich habe ja eine Auflösung von (40*4) * 96 und muss in horizontaler Richtung mit 4 Phasen incl. EOR Befehlen arbeiten, in vertikaler Richtung habe ich eine sehr lange Tabelle, damit ich nicht ständig den y-Displaywert berechnen muss. Und dann muss man ja auch noch 4 Fälle unterscheiden (dieser Ansatz macht nur eine Fall) - nämlich wenn die Steigung Minus und kleiner Eins ist. Eine kleine Gerade zeichnen auf Assembler... klingt sooo einfach und ist so schwierig!!!
jetzt habe ich mal für verschiedene Steigungen die Gerade mit Start- und Zielpunkt verglichen ... und oh Wunder, wie schon vermutet runde ich ja den "Fehler" einfach weg und das macht sich natürlich bemerkbar... die Gerade erreicht den Endpunkt meistens nicht ... Also wird nun der Algorithmus eingepflegt 😉
Nun habe ich den Algorithmus endlich korrekt umsetzen können. Ich habe also den einfachen Bresenham-Algorithmus genommen - dabei muss man beachten, daß er so nur für einen Quadranten gilt mit positiver Steigung... alle anderen Fälle lassen sich dann aber entsprechend ableiten. Ich habe das ganze für Antic D konzipiert, also wie oben beschrieben mit entsprechender Displaylist. Die Bewegung in y-Achse läuft über 2 lange Tabellen und in x-Achse mit Berücksichtigung der 4-Bit-Phasenverschiebung. Alles deutlich komplizierter als gedacht.... Meinen ersten Ansatz musste ich verwerfen, da zu ungenau. Der Bresenham-Algorithmus funktionierte bei mir nicht so wie gedacht, da fehlte noch ein x 4 bei dx ... keine Ahnung warum. Habe ich da irgendwo unbewusst ein /4 eingebaut?? 4x dx muss man vermeiden, da man bei hohen dx über die 255 Grenze kommt, also addiert man zum Fehler einfach 4x dx !! Jedenfalls so geht es jetzt ganz wunderbar!! Hier der Code vom Algorithmus, wer Interesse am Gesamtcode hat einfach melden... wäre das ein Extrabeitrag fürs Magazin?? 😀
;------ Bresenham-Algorithmus ----
mva dx fehler
lsr fehler ; laut Bresenham wird der Fehler halbiert
@
#if .byte y1<y2 ; y1 = x und y2 = xend
;-------- x=x+1-----
ldy y1 ; mein x
jsr xrichtung ; Phasenverschiebung increment horizontal x+1
;-------------------
sec
lda fehler
sbc dy
sta fehler
#if .byte fehler>#128 ; =<0
;--------- y=y+1-----
inx ; mit x lade ich hier die Displaywerte aus einer Tabelle
inx ; für die Bewegung in vertikaler Richtung, 2x inx wegen
mwa convx,x jump ; jeweils 2 Bytes auslesen - das geht dann als selbstmod.
; Code bei jump1 rein --> jsr 0 springt dann jeweils an:
; xx0 lda 256*156,y
; eor phase
; sta 256*156,y
; rts
;--------------------
clc
lda fehler
adc dx ; hier muss man 4x dx zum Fehler wieder addieren
adc dx ; also quasi fehler + 4 x dx (geht aber nicht für hohe dx - also 4 x addieren)
adc dx
adc dx
sta fehler
#end
;---------- Print Punkt ------
jsr jump1
;-----------------------------
jmp @-
#end
jmp * ; Programm stoppt hier
jump1 jump = *+1
jsr 0
rts
;-------------- Ende -----------------------------
.proc xrichtung
#if .byte horiz=#3
mva #2 phase
mva #0 horiz
inc y1
rts
#end
#if .byte horiz=#2
mva #8 phase
inc horiz
rts
#end
#if .byte horiz=#1
mva #32 phase
inc horiz
rts
#end
#if .byte horiz=#0
mva #128 phase
inc horiz
rts
#end
rts
.endp
Dr. Irata schrieb: wäre das ein Extrabeitrag fürs Magazin?? :D
Ja !!
https://mastodon.social/@cstrotm https://abbuc.social
... jetzt plötzlich - wie logisch - ist mir gerade klar geworden, warum ich den Faktor 4 für dx brauche, damit es stimmt.... meine Auflösung in x-Richtung ist ja theoretisch 160, aber da ich 4bit * 40 = 160 habe, rechne ich ja die ganze Zeit in x-Richtung mit 1/4... das macht natürlich den Algorithmus falsch - bzw. man muss das mit Faktor 4 korrigieren !!
Nun kann ich die anderen Fälle programmieren, damit kann man die Gerade in alle Richtungen zeichnen. Im Anschluss mache ich eine kleine animierte Demo...
Ich habe in meinem PDF Archiv noch Artikel zu diesem Thema gefunden (siehe Anhänge).
https://mastodon.social/@cstrotm https://abbuc.social
Dr. Irata schrieb: Nun kann ich die anderen Fälle programmieren, damit kann man die Gerade in alle Richtungen zeichnen. Im Anschluss mache ich eine kleine animierte Demo...
Es werden weniger Fälle, wenn Start- und Endpunkt vorher getauscht werden, falls sie "ungünstig" liegen....
Noch ein Tipp: Beim 6502 ist es schneller man adressiert 16bit über 2 Tabellen (Hi- und Low-Byte getrennt).
Mal ein Auszug aus meiner Grafik-Lib:
; Calculates and returns actual adress of line respective to screen base address,
; row offset value and given y/line number
; BYTE* __fastcall__
; Screen_GetRowAddress(BYTE nRow_);
.export _Screen_GetRowAddress
.proc _Screen_GetRowAddress
tay ; line to table index
lda _ScreenRowAdrTableL, Y ; access table (low)
ldx _ScreenRowAdrTableH, Y ; access table (high)
rts
.endproc
vielen vielen Dank für die inspirierende Ideen... schon cool, was alles möglich ist mit dem kleinen A8...
... also ich habe meine Tabelle / Tabellen folgendermaßen angelegt:
Wenn eine Bewegung vertikal erfolgt, lade ich per selbstmodifizierenden Code eine entsprechende 16 Bit Adresse (die ist und bleibt fix und steht daher am Beginn des Programmes) in den JSR-Befehl, per JSR springe ich dann jeweils zu der kleinen und kurzen Routine, die den Plot in der jeweiligen Zeile macht. Jegliche Rechnerei wird dadurch vermieden... ob das jetzt besonders schnell und gut ist, weiß ich nicht - besser als dauernd berechnen sicherlich.
...
mwa convx,x jump ; dies ist der selbstmodifizierende Part
...
...
jump1 jump = *+1 ; aus der Tabelle conv erhält jump die Sprungadresse, durch *+1 wird die adresse hinter jsr gelegt
jsr 0
rts
....
;Tabelle der einzelnen Adressen - für jede Zeile eine:
convx .word $2200,$220a,$2214,$221e,$2228,$2232,$223c,$2246
.word $2250,$225a,$2264,$226e,$2278,$2282,$228c,$2296
.word $22a0,$22aa,$22b4,$22be,$22c8,$22d2,$22dc,$22e6
.word $22f0,$22fa,$2304,$230e,$2318,$2322,$232c,$2336
.word $2340,$234a,$2354,$235e,$2368,$2372,$237c,$2386
.word $2390,$239a,$23a4,$23ae,$23b8,$23c2,$23cc,$23d6
.word $23e0,$23ea,$23f4,$23fe,$2408,$2412,$241c,$2426
.word $2430,$243a,$2444,$244e,$2458,$2462,$246c,$2476
.word $2480,$248a,$2494,$249e,$24a8,$24b2,$24bc,$24c6
.word $24d0,$24da,$24e4,$24ee,$24f8,$2502,$250c,$2516
.word $2520,$252a,$2534,$253e,$2548,$2552,$255c,$2566
.word $2570,$257a,$2584,$258e,$2598,$25a2,$25ac,$25b6
; ein Ausschnitt der Plotroutinen. Diese beginnt zwingend bei $2200
xx0 lda 256*156,y
eor phase
sta 256*156,y
rts
xx1 lda 256*156+50,y
eor phase
sta 256*156+50,y
rts
xx2 lda 256*156+100,y
eor phase
sta 256*156+100,y
rts
xx3 lda 256*156+150,y
eor phase
sta 256*156+150,y
rts
xx4 lda 256*156+200,y
eor phase
sta 256*156+200,y
rts
.......
xx95 lda 256*175,y
eor phase
sta 256*175,y
rts
Irgendwer schrieb: Noch ein Tipp: Beim 6502 ist es schneller man adressiert 16bit über 2 Tabellen (Hi- und Low-Byte getrennt).
Mal ein Auszug aus meiner Grafik-Lib:
``` ; Calculates and returns actual adress of line respective to screen base address, ; row offset value and given y/line number ; BYTE* fastcall ; Screen_GetRowAddress(BYTE nRow_);
.export _Screen_GetRowAddress .proc _Screen_GetRowAddress tay ; line to table index lda _ScreenRowAdrTableL, Y ; access table (low) ldx _ScreenRowAdrTableH, Y ; access table (high) rts .endproc ```
bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???
Und noch zwei Artikel gefunden:
https://mastodon.social/@cstrotm https://abbuc.social
Dr. Irata schrieb: bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???
Halleluja, so wie Du das gemacht hast, wäre mir gar nicht eingefallen. Mit haben schon die z.B. 192*2 Bytes (Antic F) für die Zeilenadresstabelle weh getan, aber für jede Zeile noch mal 9 Bytes für die Plot-Routine ist schon beachtlich - auch deswegen, weil Du für typische Anwendungsfälle nicht mit EOR auskommst, sondern AND zum Löschen und OR zum "Zeichnen" brauchst (was den Code nochmal aufbläht).
Ich benutze nicht MADS und tue mich mit den "mwa/mva"-Macros immer schwer. Aber optimal scheint mir das Vorgehen nicht zu sein. (Ich verstehe auch nicht ganz Deinen +50, +100, +150 Offset (falls Du nicht eine spezielle Display-List hast, sollten Deine Zeilen 40 Bytes breit sein...?))
Ganz klassisch würde das EOR-Plotten ungefähr so aussehen:
; Routine zum Plotten, X = x-Koordinate; Y = Y-Koordinate, zpPtr = 16-Bit Wort in der Zero-Page
Plot:
lda _ScreenRowAdrTableL, Y ; access table (low)
sta zpPtr
lda _ScreenRowAdrTableH, Y ; access table (high)
sta zpPtr+1
txa ;
lsr a ; / 2
lsr a ; / 4 ( 4 Pixel / Byte )
tay ; = zeilen offset
; hier könnte code stehen der 'phase' (aus Deinem Code) errechnet
; aus der X-coordinate 2 bits nimmt für eine Maske aus einer Tabelle
; txa
; and #3
; tax
; lda PixelMask, x ; farbabhängig
; sta phase
lda (zpPtr), Y
eor phase
sta (zpPtr), Y
rts
PixelMask:
.byte %00000011
.byte %00001100
.byte %00110000
.byte %11000000
Es gibt noch genug zum Austoben: Der Trick bei einer Linienroutine ist nicht einzelne Pixel zu plotten, sondern das Wissen, dass sie benachbart sind code-technisch elegant auszunutzen... (z.B. selbe Zeile, selbes Byte etc.)
Noch ein Tipp: Statt
jsr irgendwohin
rts
kann man auch
jmp irgendwohin
schreiben und spart Zeit und ein Byte...
Und noch ein Hinweis: Die Literatur, die 'cas' hier verlinkt hat ist sicherlich interessant, aber wenn sie für den C64 ist sehr mit Vorsicht zu genießen. Der C64 hat ein ganz anderen Bildschirmspeicheraufbau, was die Sache noch komplizierter macht...
Weiterhin viel Spaß beim Entdecken!
... tatsächlich hatte ich aus älteren Überlegungen (Feinscrol/Grobscrol) die Displaylist ganz anders aufgebaut. Für horizontales Feinscrolling braucht man ja eine Breite von 48 statt 40 (ich habe gleich 50 genommen, weil es mir übersichtlicher erschien) - jede Zeil der Displaylist hat entsprechend einen eigenen Sprungbefehl mit entsprechender Adresse wegen des dann auch zu erwartenden Grobscroll mit Displaylistmanipulation. Da ich aber keinen Feinscroll brauche bei dem Programm, macht es Sinn, die Displaylist wieder ganz normal zu strukturieren. Die Plotroutine sieht gut aus - ich werde das umbauen. Danke für alle Hinweise...
Irgendwer schrieb:
Dr. Irata schrieb: bedeutet das, wenn ich zum Beispiel statt mwa convx,x jump zunächst mva conv1 jump1 für low Byte und dann mva conv2 jump2 für high Byte selbstmodifiziedend aus 2 Tabellen hole und hinter jsr 0 platziere - ist das schneller???
Halleluja, so wie Du das gemacht hast, wäre mir gar nicht eingefallen. Mit haben schon die z.B. 192*2 Bytes (Antic F) für die Zeilenadresstabelle weh getan, aber für jede Zeile noch mal 9 Bytes für die Plot-Routine ist schon beachtlich - auch deswegen, weil Du für typische Anwendungsfälle nicht mit EOR auskommst, sondern AND zum Löschen und OR zum "Zeichnen" brauchst (was den Code nochmal aufbläht).
Ich benutze nicht MADS und tue mich mit den "mwa/mva"-Macros immer schwer. Aber optimal scheint mir das Vorgehen nicht zu sein. (Ich verstehe auch nicht ganz Deinen +50, +100, +150 Offset (falls Du nicht eine spezielle Display-List hast, sollten Deine Zeilen 40 Bytes breit sein...?))
Ganz klassisch würde das EOR-Plotten ungefähr so aussehen:
``` ; Routine zum Plotten, X = x-Koordinate; Y = Y-Koordinate, zpPtr = 16-Bit Wort in der Zero-Page Plot: lda _ScreenRowAdrTableL, Y ; access table (low) sta zpPtr lda _ScreenRowAdrTableH, Y ; access table (high) sta zpPtr+1 txa ; lsr a ; / 2 lsr a ; / 4 ( 4 Pixel / Byte ) tay ; = zeilen offset
; hier könnte code stehen der 'phase' (aus Deinem Code) errechnet ; aus der X-coordinate 2 bits nimmt für eine Maske aus einer Tabelle ; txa ; and #3 ; tax ; lda PixelMask, x ; farbabhängig ; sta phase lda (zpPtr), Y eor phase sta (zpPtr), Y rtsPixelMask: .byte %00000011 .byte %00001100 .byte %00110000 .byte %11000000 ```
Es gibt noch genug zum Austoben: Der Trick bei einer Linienroutine ist nicht einzelne Pixel zu plotten, sondern das Wissen, dass sie benachbart sind code-technisch elegant auszunutzen... (z.B. selbe Zeile, selbes Byte etc.)
Noch ein Tipp: Statt
jsr irgendwohin rtskann man auch
jmp irgendwohinschreiben und spart Zeit und ein Byte...
Und noch ein Hinweis: Die Literatur, die 'cas' hier verlinkt hat ist sicherlich interessant, aber wenn sie für den C64 ist sehr mit Vorsicht zu genießen. Der C64 hat ein ganz anderen Bildschirmspeicheraufbau, was die Sache noch komplizierter macht...
Weiterhin viel Spaß beim Entdecken!
... mit welcher Umgebung programmierst du denn??
cas schrieb: Und noch zwei Artikel gefunden:
Eine Info zum C64 und dessen HiRes Grafik.
Ein Index sieht so aus... 0, 1, 2, 3, ... 39, 40,41,42... ...
Ein Index beim C64 sieht so aus... 0,8,16,24, ... 312, 1,9,17, 2,10,18, 3,11,19, ... 7,15,23,...
320,328,... 321,... ...
Das sollte man berücksichtigen, wenn man sich C64-Linienalgorithmen ansieht und versucht diese zu verstehen.
LG Lars
Ich bin auch kein Fan von MADS und mva/mwa. Das wird sich erst ändern, wenn es den Assembler native auf Linux gibt. BTW: Wine ist nicht Linux.
LarsImNetz schrieb: Ich bin auch kein Fan von MADS und mva/mwa. Das wird sich erst ändern, wenn es den Assembler native auf Linux gibt. BTW: Wine ist nicht Linux.
Hallo Lars,
warum "wenn", den gibt es doch schon lange (eigendlich seit immer) "nativ" unter Linux:
apt install fpc
git clone https://github.com/tebe6502/Mad-Assembler
cd Mad-Assembler
fpc -Mdelphi -vh -O3 mads.pas
sudo cp mads /usr/local/bin
Ich kann Dir gerne auch ein "mads" binary für i686/amd64/arm/aarch64/m68k kompilieren.
https://mastodon.social/@cstrotm https://abbuc.social
passt schon, hab ihn gerade selbst gebaut.
So, hier mal eine etwas schnellere Line-Zeichen-Routine. Es gab mal irgendwo einen Source mit 8 Versionen, das hier ist die letzte davon.
Die Routine schafft locker 300 Linien pro Sekunde. (rand(160), rand(192),rand(160), rand(192)) ist leider etwas ungenau, dafür verdammt flott.
Die Parameterübergabe ist für meinen Compiler, ähnlich wie beim cc65. Per (heap_ptr),y realisiert. Wenn man sich die komplizierte, teure Parameterübergabe spart, ist diese Routine noch schneller. Der Code ist kompatibel zum Atasm Assembler. Der Code zeichnet 4 Pixel gleichzeitig, mehr hab ich bisher auch nicht verstanden.
Wirklich das schnellste, was ich bisher gesehen habe. Ich habe auch den Code von ERU, zum Vergleich, die schafft ca. 216 Linien pro Sekunde, nur um mal ein paar Zahlen zu nennen. Mit einfachem Bresenham komme ich in meinem Compiler nicht über 80 Linien pro Sekunde, was aber am expliziten PLOT(x,y) liegt.
Wer die Routine nutzen möchte, sollte die @MULT40_low und _high Tabelle noch setzen, hab ich hier nicht mit angegeben.
LG Lars
.LOCAL
; TODO
; Dieser LINE Algorithmus funktioniert nur
; in graphics 7 und 15 (40 Bytes breit)
; bis 160 x 192!!! Weil nur 8 Bit breit
; ist dafuer sehr schnell, leider ungenau => eher unbrauchbar
; BITMSK = $6E
; SHFAMT = $6F
;ROWCRS = $54
;COLCRS = $55
;OLDROW = $5A
;OLDCOL = $5B
;ROWAC = $70
;ROWADC = $72
;CFLAG = $74
;RFLAG = $75
;DELTAROW= $76
;DELTACOL= $77
;ATACHR = $02FB
;opcodes for self-modifying code
?_OC_BIT_0P_ = $24
?_OC_DEC_0P_ = $C6 ;11000110
?_OC_INC_0P_ = $E6 ;11100110 ;XOR 32 ;$20
?_OC_DEX_ = $CA ;11001010
?_OC_INX_ = $E8 ;11101000 ;XOR 34 ;$22
?_OC_AND_AX_ = $3D
?_OC_EOR_AX_ = $5D
?_OC_ORA_AX_ = $1D
; @REG ist bei mir ab Adresse 220 (Floating-Point-Register)
?L0 = @REG+0 ; $B0
?L1 = @REG+1 ; $B1
?L2 = @REG+2 ; $B2
?L3 = @REG+3 ; $B3
?L4 = @REG+4 ; $B4
?L5 = @REG+5 ; $B5
?L6 = @REG+6 ; $B6
?L7 = @REG+7 ; $B7
?m0 = @REG+8
?m1 = @REG+9
?m2 = @REG+10
?x0 = @REG+11
?x1 = @REG+12
?x2 = @REG+13
@SETLINECOLOR
@SETLINECOLOR_i
LDY #1 ; color 0 - 3
LDA (@HEAP_PTR),Y ; wert holen
and #3
TAX
LDY ?MASTSET,X
STY ?SET1IMASKT
STY ?SET1IMASKW
STY ?SET2IMASKT
STY ?SET2IMASKW
STY ?SET3IMASKT
STY ?SET3IMASKW
STY ?SET4IMASKT
STY ?SET4IMASKW
LDA ADRCOLMHI,X
STA ?GET1CMASKHT
STA ?GET1CMASKHW
STA ?GET2CMASKHT
STA ?GET2CMASKHW
STA ?GET3CMASKHT
STA ?GET3CMASKHW
STA ?GET4CMASKHT
STA ?GET4CMASKHW
RTS
; DRAWLINE ;v6
; LDA #1
; STA OLDROW
; LDA #153
; STA OLDCOL
; LDA #072
; STA ROWCRS
; LDA #1
; STA COLCRS
@LINE
@LINE_IIII
@FASTLINE2BIT
@FASTLINE2BIT_IIII
LDY #1 ; XSTART
LDA (@HEAP_PTR),Y ; wert holen
STA OLDCOL ; ?XSTART
LDY #3 ; YSTART
LDA (@HEAP_PTR),Y ; wert holen
STA OLDROW ; ?YSTART
LDY #5 ; XEND
LDA (@HEAP_PTR),Y ; wert holen
STA COLCRS ; ?XEND
LDY #7 ; YEND
LDA (@HEAP_PTR),Y ; wert holen
STA ROWCRS ; ?YEND
LDA OLDROW
SEC
SBC ROWCRS
BCS ?OLDROWFIRST
LDX OLDCOL ;3
LDY COLCRS ;3
STY OLDCOL ;3
STX COLCRS ;3
LDY OLDROW
SBC #0
EOR #255
JMP ?STOREROWDELTA
?OLDROWFIRST
LDY ROWCRS
?STOREROWDELTA
STA ?aw_WIDE_DELTA_RI
STA ?aw_TALL_DELTA_RI
LSR A
LSR A
STA ?X1
BNE ?NOVS2
BCC ?NOVS2
LDA #01
?NOVS2
STA ?m2
LDA @MULT40_LOW,Y
STA ?L0
LDA @MULT40_HIGH,Y
STA ?L1
TYA
CLC
ADC ?X1
TAY
LDA @MULT40_LOW,Y
STA ?L2
LDA @MULT40_HIGH,Y
STA ?L3
TYA
CLC
ADC ?m2
TAY
LDA @MULT40_LOW,Y
STA ?L4
LDA @MULT40_HIGH,Y
STA ?L5
TYA
CLC
ADC ?X1
TAY
LDA @MULT40_LOW,Y
STA ?L6
LDA @MULT40_HIGH,Y
STA ?L7
LDA OLDCOL
SEC
SBC COLCRS
BCS ?aw_HOZ_POS
?aw_HOZ_NEG
SBC #0
EOR #255
TAY
LSR A
LSR A
STA ?m1
STA ?x0
STA ?X2
BNE ?noHS1
BCC ?noHS1
LDA #1
?noHS1
STA ?m2
LDA COLCRS
SEC
SBC ?X2
STA ?GET1CMASKLW
STA ?GET1TABLW
STA ?GET1CMASKLT
STA ?GET1TABLT
SBC ?m2
STA ?GET2CMASKLW
STA ?GET2TABLW
STA ?GET2CMASKLT
STA ?GET2TABLT
SBC ?X2
STA ?GET3CMASKLW
STA ?GET3TABLW
STA ?GET3CMASKLT
STA ?GET3TABLT
SBC ?X2
STA ?GET4CMASKLW
STA ?GET4TABLW
STA ?GET4CMASKLT
STA ?GET4TABLT
LDX #?_OC_DEX_
JMP ?compARE_SLOPE
?aw_HOZ_POS
TAY
LSR A
LSR A
STA ?X2
BNE ?noHS2
BCC ?noHS2
LDA #01
?noHS2
STA ?m2
LDA COLCRS
STA ?GET1CMASKLW
STA ?GET1TABLW
STA ?GET1CMASKLT
STA ?GET1TABLT
CLC
ADC ?X2
STA ?GET2CMASKLW
STA ?GET2TABLW
STA ?GET2CMASKLT
STA ?GET2TABLT
ADC ?m2
STA ?GET3CMASKLW
STA ?GET3TABLW
STA ?GET3CMASKLT
STA ?GET3TABLT
ADC ?X2
STA ?GET4CMASKLW
STA ?GET4TABLW
STA ?GET4CMASKLT
STA ?GET4TABLT
STA ?m0
LDX #0
STX ?x0
LDX #?_OC_INX_
?compARE_SLOPE
CPY ?aw_WIDE_DELTA_RI
BCC ?aw_TALLSLOPE
BEQ ?aw_TALLSLOPE
?aw_WIDESLOPE
STY ?aw_WIDE_DELTA_CI
TYA
SEC
SBC ?m2
STA ?m1
STX ?COLADC1
LDA ?X2
BEQ ?aw_WIDESLOPE0
SEC
LDX ?x0
?aw_WIDE_LOOP
?COLADC1
INX ;2
?GET1TABLW = *+1
LDY ?TAB4DIV,X ;6
LDA (?L0),Y ;11
?SET1IMASKW = *
?GET1CMASKLW = *+1
?GET1CMASKHW = *+2
ORA $FF00,X ;15
STA (?L0),Y ;20
?GET2TABLW = *+1
LDY ?TAB4DIV,X ;24
LDA (?L2),Y ;29
?SET2IMASKW = *
?GET2CMASKLW = *+1
?GET2CMASKHW = *+2
ORA $FF00,X ;33
STA (?L2),Y ;38
?GET3TABLW = *+1
LDY ?TAB4DIV,X ;42
LDA (?L4),Y ;47
?SET3IMASKW = *
?GET3CMASKLW = *+1
?GET3CMASKHW = *+2
ORA $FF00,X ;51
STA (?L4),Y ;56
?GET4TABLW = *+1
LDY ?TAB4DIV,X ;60
LDA (?L6),Y ;65
?SET4IMASKW = *
?GET4CMASKLW = *+1
?GET4CMASKHW = *+2
ORA $FF00,X ;69
STA (?L6),Y ;74
LDA ?m1 ;77 -3
?aw_WIDE_DELTA_RI=*+1
SBC #$FF ;79 -5
STA ?m1 ;82 -8
BCS ?aw_WIDE_SKIP ;85
?aw_WIDE_DELTA_CI=*+1
ADC #$FF
STA ?m1
LDA ?L0
CLC
ADC #40
STA ?L0
BCC ?no_WIDE_H1INC
INC ?L1
CLC
?no_WIDE_H1INC
LDA ?L2
ADC #40
STA ?L2
BCC ?no_WIDE_H2INC
INC ?L3
CLC
?no_WIDE_H2INC
LDA ?L4
ADC #40
STA ?L4
BCC ?no_WIDE_H3INC
INC ?L5
CLC
?no_WIDE_H3INC
LDA ?L6
ADC #40
STA ?L6
BCC ?no_WIDE_H4INC
INC ?L7
?no_WIDE_H4INC
SEC
?aw_WIDE_SKIP
?LAST_WIDE_X = *+1
DEC ?X2 ;88
BNE ?aw_WIDE_LOOP ;91
?aw_WIDESLOPE0
RTS
;
?aw_TALLSLOPE
STY ?aw_TALL_DELTA_CI
LDA ?aw_TALL_DELTA_RI
SEC
SBC ?m2
STA ?m1
DEC ?X1
BEQ ?aw_WIDESLOPE0
BMI ?aw_WIDESLOPE0
STX ?COLADC2
LDX ?x0
?aw_TALL_LOOP
?GET1TABLT = *+1
LDY ?TAB4DIV,X ;4
LDA (?L0),Y ;9
?SET1IMASKT = *
?GET1CMASKLT = *+1
?GET1CMASKHT = *+2
ORA $FF00,X ;14
STA (?L0),Y ;19
?GET2TABLT = *+1
LDY ?TAB4DIV,X ;23
LDA (?L2),Y ;28
?SET2IMASKT = *
?GET2CMASKLT = *+1
?GET2CMASKHT = *+2
ORA $FF00,X ;32
STA (?L2),Y ;37
?GET3TABLT = *+1
LDY ?TAB4DIV,X ;4
LDA (?L4),Y ;9
?SET3IMASKT = *
?GET3CMASKLT = *+1
?GET3CMASKHT = *+2
ORA $FF00,X ;14
STA (?L4),Y ;19
?GET4TABLT = *+1
LDY ?TAB4DIV,X ;23
LDA (?L6),Y ;28
?SET4IMASKT = *
?GET4CMASKLT = *+1
?GET4CMASKHT = *+2
ORA $FF00,X ;32
STA (?L6),Y ;37
LDA ?m1 ;40
SEC ;42
?aw_TALL_DELTA_CI=*+1
SBC #$FF ;44
BCS ?aw_TALL_SKIP ;47
?aw_TALL_DELTA_RI=*+1
ADC #$FF ;
?COLADC2
INX
?aw_TALL_SKIP
STA ?m1 ;50
LDA ?L0 ;53
CLC ;55
ADC #40 ;57
STA ?L0 ;60
BCC ?no_TALL_H1INC ;63
INC ?L1
CLC
?NO_TALL_H1INC
LDA ?L2 ;66
ADC #40 ;68
STA ?L2 ;71
BCC ?no_TALLH2DEC ;74
INC ?L3
?NO_TALLH2DEC
LDA ?L4 ;53
CLC ;55
ADC #40 ;57
STA ?L4 ;60
BCC ?no_TALL_H3INC ;63
INC ?L5
CLC
?NO_TALL_H3INC
LDA ?L6 ;66
ADC #40 ;68
STA ?L6 ;71
BCC ?NO_TALLH4DEC ;74
INC ?L7
?NO_TALLH4DEC
DEC ?X1 ;77
BPL ?AW_TALL_LOOP ;80
?DREND
RTS
* = (* +$FF) & $FF00
ANDMASK
.byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
.byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
.byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
.byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
.byte 63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252,63,207,243,252
ADRCOLMLO
.byte <ANDMASK, <COLORMASK1, <COLORMASK2, <COLORMASK3
ADRCOLMHI
.byte >ANDMASK, >COLORMASK1, >COLORMASK2, >COLORMASK3
?MASTSET
.byte ?_OC_AND_AX_, ?_OC_ORA_AX_, ?_OC_ORA_AX_, ?_OC_ORA_AX_
.byte ?_OC_AND_AX_, ?_OC_EOR_AX_, ?_OC_EOR_AX_, ?_OC_EOR_AX_
;M1DIMG
; .byte 3,12,48,192
;M2DIMG
; .byte 1,4,16,64
;EMPTYDATA
; .byte 0,0,0,0
; ORG LINEDATAPAGE + 256
* = (* +$FF) & $FF00
COLORMASK1
.byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
.byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
.byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
.byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
.byte 64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1,64,16,4,1
; ORG LINEDATAPAGE + 512
* = (* +$FF) & $FF00
COLORMASK2
.byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
.byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
.byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
.byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
.byte 128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2,128,32,8,2
; ORG LINEDATAPAGE + 768
* = (* +$FF) & $FF00
COLORMASK3
.byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
.byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
.byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
.byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
.byte 192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3,192,48,12,3
; ORG LINEDATAPAGE + 1024
* = (* +$FF) & $FF00
?TAB4DIV
.byte 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9
.byte 10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19
.byte 20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29
.byte 30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,37,37,37,37,38,38,38,38,39,39,39,39
.align 256
; muessen initialisiert werden! Die zeigen auf den Graphics-Speicher, jeder Wert ist um 40 Bytes groesser
@MULT40_low
.dc 256 0
@MULT40_high
.dc 256 0
... ich sehe schon, das Thema gibt eine Menge her. Nach welchem mathematischen Prinzip arbeiten denn diese schnellen Lösungen?
Dr. Irata schrieb: ... mit welcher Umgebung programmierst du denn??
cc65/ca65
eigentlich versuche ich inzwischen soviel wie geht in cc65 zu schreiben und erst wenn es zeitkritisch wird, entweder cc65 zu verbessern 😀 oder auf Assembler zu wechseln. Klappt bisher ganz gut.
Größte Hürde bei cc65 ist, wenn man es denn irgendwann kann, gleichzeitig die größte Hilfe: Die Linker-Configuration. Gerade beim Atari mit seinen vielen Speicherausrichtungsanforderungen (Zeichensätze, PMG, DL, Bildschirmspeicher) ist das am Anfang kompliziert - inzwischen aber für die Atari-Compound-Dateien besser unterstützt und etwas einfacher.
(Die PixelMask-Tabelle oben ist glaube ich falsch herum, um 1:40 kann das schon einmal passieren... 😉 )
Grüße!
ich habe jetzt die gesamte Displaylist angepasst und auch die Plotroutine... was noch fehlt ist die schnellere Phasenverschiebung. Leider bin ich am WE unterwegs und kann da nicht weitermachen... zunächst. Das Projekt ist höchst spannend. Ich habe eine Zählerroutine mit reingemacht, damit ich die Geschwindigkeit testen kann.... bislang schafft die Routine ca 90 lange Linien pro Sekunde in Pal. Jetzt das noch weiter optimieren... ich möchte mindestens 150 / Sekunde zeichnen können, dann gehts weiter mit 3D
... ich habe gerade mal die alte Routine für die Phasenverschiebung komplett rausgenommen - die Gerade sieht natürlich jetzt falsch aus, aber die Geschwindigkeit nimmt damit dramatisch zu: Fast 500 Linien pro Sekunde zeichnet die Routine mit dem Bresenham-Algorithmus. Der Bremsklotz ist also die Unterroutine der Phasenverschiebung. Das ahnte ich schon, da ich die Routine ohne Optimierung gebaut habe. Hier gilt es jetzt anzusetzen und da habe ich auch schon einige Ideen. Eigentlich geht ja der Bresenham immer um einen X-Wert voran und ab und zu halt mal um einen Y-Wert nach oben oder unten. Das schnellste wird wohl sein, ein wenig Speicher zu opfern und die Routine einfach 4x hintereinander laufen zu lassen - jeweils mit phasenverschobenen Wert der zu platten ist. Dann gibt es praktische keine relevante Verzögerung und ich hoffe damit auf 300-400 Linien pro Sekunde zu kommen - damit könnte man arbeiten.
Danach programmiere ich die ganzen Spezialfälle (positive Steigung, negative Steigung, jeweils Steigung >1 und <1, horizontale Linie, vertikale Linie, jeweils Steigung genau 1 / -1...... es werden also wohl 10 Fälle jeweils mit 4x Code wegen der Phasenverschiebung. Großer Aufwand - Maximale Geschwindigkeit....
... nochmal ein kurzes Wort zu MADS:
Eingebunden mit WUDSN in Eclipse mit dem Emulator ist das für mich wirklich eine optimale Umgebung, um mit moderner Technik Assemblercode für unseren geliebten Atari zu entwickeln!! Ich könnte mir nichts besseres vorstellen - vielleicht wäre Action! mal interessant. Kann man das in Eclipse einbinden???
[quote="Dr. Irata" post_id=15255 time=1685089261 user_id=250] Kann man das in Eclipse einbinden??? [/quote]
ACTION! läuft auf dem Atari als Cart, da müsste man den Emulator per Script "fernsteuern". Das habe ich noch nicht getestet, ob es einen Emulator gibt, der das kann. Wäre Interessant das mal herauszufinden.
Unter
New Frontiers in High-Level 6502 Programming https://8bitworkshop.com/docs/posts/2018/higher-level-6502-programming.html#higher-level-6502-programming
gibt es eine lange Liste von sehr interessanten (zum Teil neuen) Programmiersprachen für den A8. Ich suche noch Mitstreiter, welche an einer Artikel-Serie für das ABBUC Magazin mitmachen um diese Sprachen zu testen und auch von der Code-Qualität zu vergleichen.
Bei Interesse bitte melden.
https://mastodon.social/@cstrotm https://abbuc.social
... interessant mit den Sprachen, zeitlich schaffe ich das leider im Moment nicht, auch habe ich ja nur Mac und die meisten Entwicklungen laufen nur auf Windows...
Thema Plot/Drawto:
Habe jetzt mal kurz in der Vormittagszeit den Code wie oben geschrieben vervierfacht und so das "Problem" mit der Phasenverschiebung sehr einfach gelöst... Geschwindigkeitszuwachs von ca. 90 Linien/Sekunde auf 220 Linien/Sekunde. Mal sehen, ob ich das noch weiter steigern kann...
... 250 ... mehr geht nicht! Das betrifft natürlich gemessenen Linien, die zwischen mittellang und sehr lang geplottet werden - also die ganze Diagonale des Bildschirmes bei 160/96 Auflösung betrifft. Wenn ich jetzt in einem 3D Spiel von deutlich kürzeren Linien ausgehe, dann schaffe ich so ca. 500-600 Linien oder mehr pro Sekunde. Das weitere Vorgehen wird jetzt sein, eine komplette Plotroutine für alle Gerade zu schreiben, dann möchte ich eine Linie animiert darstellen. Danach wird das ganze fürs nächste Heft aufgearbeitet incl. Dokumentation und Code.
Anschließend wird dieses Thema hier geschlossen und ich gehe weiter in die nächste Planung von 3D TempleOfEris, wo ich zunächst ein reines 3D-Raumgerüst erstellen möchte, was man mit dem Joystick entsprechend der Bewegung durch den Raum steuern kann. Danach kommen die Wandfüllroutinen - also die mögliche Oberfläche (diesen Part stelle ich mir sehr schwierig vor).
Danach sollten (wenn ich überhaupt so weit komme) die Aliens, Schüsse, Kollisionserkennung folgen, dann das gesamte Labyrinthdesign... (in ca. 10 Jahren bin ich dann vielleicht fertig 😂 )
... jetzt habe ich die Plotroutine fertig und alle Spezialfälle (Richtungen, Steigungen) sind drin und funktionieren - ein kleiner Fehler muss noch drin sein habe ich gerade gesehen - und kurz mal eine kleine allerdings nicht sehr gute Routine geschrieben, um eine Linie zu zeichnen und die per Random über den Bildschirm zu bewegen. Damit ist das Kapitel hier fertig... ich arbeite das noch fürs Magazin auf und gehe dann zurück zu Temple Of Eris!
vielleicht noch per Pageflipping arbeiten und dann Quasi die neue Zeile erst anzeigen wenn sie fertig gezeichnet ist...
... ich habe jetzt auch die Drawfehler raus und mache den Plot jetzt im VBI, damit das etwas besser aussieht (Danke Janko für den Hinweis). Die Bewegung ist zufallsgesteuert und daher nicht so schön "rund", man müsste Bewegungsmuster hinterlegen, damit es eine feine Demo wird, das habe ich jetzt nicht noch gemacht... Hier aber nochmal ein kleiner Ausschnitt aus der Draw-Bewegung:
Wozu willst du die Linie eigentlich verwenden?
ursprünglich wollte ich für mein nächstes Spiel schauen, ob es möglich ist eine Art Ego-Shooter zu machen mit einem 3D Labyrinth... da wurde mir schnell klar, daß ich dafür ganz viele Linien zeichnen lassen muss. Linien zeichnen in Assembler - gar nicht so einfach. Daher jetzt dieser Beitrag incl. Bresenham- Algorithmus. Ob ich das am Ende hinbekomme? Fraglich... erstmal alles im Rahmen einer Machbarkeitsstudie 😉
Noch gefunden (und gerade geschaut):
Let's Code MS DOS 0x20: Bresenham Line Drawing https://www.youtube.com/watch?v=pMZ-nWpHJdo
https://mastodon.social/@cstrotm https://abbuc.social
sehr cool... allerdings brauche ich jetzt noch einen Füllalgorithmus 😉
Dr. Irata schrieb: sehr cool... allerdings brauche ich jetzt noch einen Füllalgorithmus 😉
Na ja, wenn Du ein ausgefülltes "Labyrinth" haben möchtest, brauchst Du keine Linienzeichenroutine. Der einzig gangbare Weg, so etwas einigermaßen zügig auf dem Atari hinzubekommen ist ein sogenannter "Raycaster". Zu diesem Thema gibt es sehr viel Literatur, Youtube-Tutorials, Beispielcode.
Deine Linienroutine ergibt allerdings Sinn, falls Du eine Drahtgitter 3d-Umgebung erstellen möchtest. Dann brauchst Du aber keinen 'Füllalgorithmus'...
... bin mir da noch nicht so ganz sicher, wie es wird.... zunächst probiere ich mal aus die Flächen auch mit vertikalen Drawlinien zu "füllen" - so war mein Plan. Die Routinen sind ja schnell und einfach und wenn ich die schrägen Geraden zeichne, dann kann ich gleichzeitig die Linien mit vertikalen verbinden. Ob das gut funktioniert, weiß ich nicht... so etwas habe ich ja noch nie gemacht.
Das Thema lässt mich nicht los ... heute gab es auf HackerNews (https://news.ycombinator.com) einen Link zu diesem Blog-Post
BRR Lines A new line drawing method for the cycle savvy http://www.quiss.org/boo/
Dort hat jemand aus dem C64-Land einen Linien-Algorithmus, welcher oft schneller als Bresenham ist. Ist C64, also anderer Speicher-Layout, aber vielleicht für den A8 adaptierbar.
https://mastodon.social/@cstrotm https://abbuc.social
vielen Dank ... mega spannend
Hi, hier mal eine simple Line-Demo.
Die zeichnet 17 Pixel auf den Screen. Die Pixel bewegen sich alle gleich schnell in unterschiedliche Richtungen. Erreicht ein Pixel den Rand, fängt er wo anders wieder an.
Wenn der Abstand zwischen 2 Pixeln eine gewisse Schwelle erreicht hat, wird zwischen ihnen eine Linie gezeichnet. Je nach Abstand unterschiedlich hell. Der Algorithmus für die Abstände ist teuer (~O(n^2/2))
Als Line-Routine hab ich die von ERU verwendet (mal in AtariAge gefunden), da dieser saubere Linien zeichnet. Die Rattenschnelle Line-Version hab ich auch mal probiert, aber die Animation ist nicht merklich flotter, dafür fällt extrem stark auf, wie schlecht der Line-Algorithmus wirklich ist.
Als DoubleBuffer habe ich mir etwas zusammengezimmert, es ist nicht perfekt, aber besser als Flackern oder immer den ganzen Screen kopieren.
Nett anzusehen, aber als Speed-Test nicht zu gebrauchen.
LG Lars
... wie funktioniert denn der Algorithmus von Eru??
Wie genau, hab ich nicht analysiert, aber hier hab ich den her: https://forums.atariage.com/topic/231690-known-fast-line-algorithms/
Der superschnelle ist hier: https://forums.atariage.com/topic/211628-fast-line-drawing/
Und Lines in Chars gibt es dann hier: http://codebase64.org/doku.php?id=base:lines
LG Lars
Neues Video über schnelle Computergrafik von PCRetroTech:
Animating Ellipses on a Vintage 386 Computer https://www.youtube.com/watch?v=d8ulXJZD0P8
erklärt die Algorithmen hinter Linien, Kreise und Ellipsen
https://mastodon.social/@cstrotm https://abbuc.social
.... nach längerer Zeit doch nochmal ein Aspekt zu diesem Thema:
In meinem Raycaster beschäftige ich mich ja gerade mit der Frage, wie kann ich die Wände besser darstellen. Dazu will ich jetzt Bresenham und eine Art Plot / Drawto - Option einbauen und nutzen. Also habe ich mich zwangsläufig wieder mit Bresenham beschäftigt und wollte gerade die alten Algorithmen rauskramen und dann in den Code einbauen. Dann kam mir aber die Erkenntnis, daß ich damals ja schon Bresenham in meinem Raycaster drin habe, allerdings nicht als Algorithmus (mit langwieriger Rechenzeit), sondern als Tabelle. Da sind also vorgefertige "Strahlen" mit voller Rotation um 360 Grad, kostet knapp 2,5 kB Diese "Strahlen" müsste man ja dann aber auch für eine Drawto-Routine nutzen können und das dürfte echt schnell sein... das werde ich hier zunächst mal bauen!
Also eine neue sehr schnelle Drawto-Routine in Assembler....